package com.njxxted.activiti.common.util;

import lombok.Data;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;

/**
 * xml解析工具
 *
 * @author edit by 2015-11-2 下午3:43:14
 */
@Data
public class XmlUtil {

    private static final Logger logger = LoggerFactory.getLogger(XmlUtil.class);

    private Document doc;
    private Element root;

    /**
     * 构造方法
     *
     * @param xml xml结构字符串
     * @throws DocumentException
     */
    public XmlUtil(String xml) throws DocumentException {
        SAXReader reader = new SAXReader();
        doc = reader.read(new StringReader(xml));
        root = doc.getRootElement();
    }

    /**
     * 构造方法
     *
     * @param is xml文件流
     * @throws DocumentException
     */
    public XmlUtil(InputStream is) throws DocumentException {
        SAXReader reader = new SAXReader();
        doc = reader.read(is);
        root = doc.getRootElement();
    }

    /**
     * 获取节点文本
     *
     * @param xmlPath XPath字符串
     *                如果XPath的开头是一个斜线（/）代表这是绝对路径。
     *                如果开头是两个斜线（//）表示文件中所有符合模式的元素都会被选出来
     *                <p>
     *                具体可以参考http://blog.sina.com.cn/s/blog_6e82a8530100w5ky.html
     * @return
     */
    public String getSingleNodeText(String xmlPath) {
        Node node = root.selectSingleNode(xmlPath);
        return node.getText();
    }

    /**
     * 获取指定节点的指定属性值
     *
     * @param xmlPath  XPath字符串
     * @param attrName 属性名称
     * @return
     */
    public String getNodeAttribute(String xmlPath, String attrName) {
        Node node = root.selectSingleNode(xmlPath);
        if (!attrName.startsWith("@")) {
            attrName = "@" + attrName;
        }
        return node.valueOf(attrName);
    }

    /**
     * 获取指定节点的首个子节点名称
     *
     * @param xmlPath
     * @return
     */
    public String getFirstNodeName(String xmlPath) {
        List nodeList = root.selectNodes(xmlPath);
        for (Iterator i = nodeList.iterator(); i.hasNext(); ) {
            Element node = (Element) i.next();
            for (Iterator j = node.elementIterator(); j.hasNext(); ) {
                Element curnode = (Element) j.next();
                return curnode.getName();
            }
        }
        return null;
    }


    /**
     * 获取节点集合
     * 目前仅支持2级结构
     *
     * @param xmlPath XPath字符串
     *                使用举例：
     *                <data>
     *                <row>
     *                <id>11</id>
     *                <name>sld</name>
     *                </row>
     *                <row>
     *                <id>22</id>
     *                <name>dwd</name>
     *                </row>
     *                </data>
     *                <p>
     *                getNodeMap("/data/row") 返回2个map分别对应11和22
     * @return
     */
    public List<Map<String, Object>> getNodeTextList(String xmlPath) {
        List nodeList = root.selectNodes(xmlPath);
        List mapList = new ArrayList<Map<String, Object>>();
        for (Iterator i = nodeList.iterator(); i.hasNext(); ) {
            Element node = (Element) i.next();
            Map<String, Object> map = new HashMap<String, Object>();
            for (Iterator j = node.elementIterator(); j.hasNext(); ) {
                Element curNode = (Element) j.next();
                //System.out.println(curNode.getName()+">>>>>"+curNode.getText());
                map.put(curNode.getName(), curNode.getText());
            }
            mapList.add(map);
        }
        return mapList;
    }


    /**
     * 获取节点集合
     *
     * @param xmlPath
     * @return
     */
    public Map<String, Object> getNodeTextMap(String xmlPath) {
        Map<String, Object> map = new HashMap<String, Object>();
        List nodeList = root.selectNodes(xmlPath);
        for (Iterator i = nodeList.iterator(); i.hasNext(); ) {
            Element node = (Element) i.next();
            for (Iterator j = node.elementIterator(); j.hasNext(); ) {
                Element curNode = (Element) j.next();
                //System.out.println(curNode.getName()+">>>>>"+curNode.getText());
                map.put(curNode.getName(), curNode.getText());
            }
        }

        return map;
    }


    public static void main(String[] args) throws DocumentException {
        String xmlString = "<INFO>" +
                " <OPERATION ACTION=\"UPDATE\">" +
                "		<DEPARTMENT_MODULE>" +
                "			<RISESHOWORDER>10005</RISESHOWORDER>" +
                "			<DEPARTMENT_GUID>{2017A898-0000-0000-5D1A-D6B300000045}</DEPARTMENT_GUID>" +
                "			<DEPARTMENT_FULLNAME>老年大学</DEPARTMENT_FULLNAME>" +
                "			<DEPARTMENT_DN>ou=老年大学,ou=老干部局,o=浦口区</DEPARTMENT_DN>" +
                "			<department_guid>{2017A898-0000-0000-5D1A-D6B300000045}</department_guid>" +
                "			<DEPARTMENT_ADDRESS/>" +
                "			<DEPARTMENT_PHONE/>" +
                "			<DEPARTMENT_FAX/>" +
                "			<DEPARTMENT_DEPTMANAGER/>" +
                "			<DEPARTMENT_DEPTLEADER/>" +
                "			<DEPARTMENT_ISDELETED>0</DEPARTMENT_ISDELETED>" +
                "			<DELETE_DESC/>" +
                "			<DEPARTMENT_DESC/>" +
                "			<DEPARTMENT_XINGZHI/>" +
                "			<SUPERIOR_GUID>{2017A898-FFFF-FFFF-EB90-CDCC00000C28}</SUPERIOR_GUID>" +
                "		</DEPARTMENT_MODULE>" +
                "	</OPERATION>" +
                "</INFO>";

        XmlUtil xu = new XmlUtil(xmlString);
		/*//print result : {2017A898-0000-0000-5D1A-D6B300000045}
		System.out.println(xu.getSingleNodeText("/INFO/OPERATION/DEPARTMENT_MODULE/DEPARTMENT_GUID"));
		//print result : UPDATE
		System.out.println(xu.getNodeAttribute("/INFO/OPERATION","ACTION"));
		//print result : DEPARTMENT_MODULE
		System.out.println(xu.getFirstNodeName("/INFO/OPERATION"));
		
		Map<String,Object> map = xu.getNodeTextMap("/INFO/OPERATION/DEPARTMENT_MODULE");
		//print result : 15
		System.out.println(map.size());
		
		List<Map<String,Object>> lst = xu.getNodeTextList("/INFO/OPERATION/DEPARTMENT_MODULE");
		//print result : 1
		System.out.println(lst.size());
		
		System.out.println(lst.get(0).get("DEPARTMENT_FULLNAME"));*/
        System.out.println(getReturnXml("111111111111", "2222222222222"));
    }

    private static String getReturnXml(String _status, String _desc) {
        String xmlTemplate = "<SyncMessage>" +
                "<status>%s</status>" +
                "<errorMessage>%s</errorMessage>" +
                "</SyncMessage>";

        return String.format(xmlTemplate, _status, _desc);
    }

    /**
     * 格式化XML文档
     *
     * @param document xml文档
     * @param charset  字符串的编码
     * @param istrans  是否对属性和元素值进行转移
     * @return 格式化后XML字符串
     */
    public static String formatXml(Document document, String charset, boolean istrans) {
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding(charset);
        StringWriter sw = new StringWriter();
        XMLWriter xw = new XMLWriter(sw, format);
        xw.setEscapeText(istrans);
        try {
            xw.write(document);
            xw.flush();
            xw.close();
        } catch (IOException e) {
            logger.debug("格式化XML文档发生异常，请检查!");
            e.printStackTrace();
        }
        return sw.toString();
    }
}
